import java.io.BufferedReader;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.Calendar;
import java.util.Iterator;
import java.util.List;
import java.io.File;


/**
 * The TermFinder is a wrapper for GO-Term-finder
 * We can possibly modify it or inherit it and implement other type of enrichment tests
 * @author odedmagg
 *
 */
public class TermFinder extends AnnotationProvider {
	/**
	 * A struct representing term search results.
	 * Contains number of genes among the members that were annotated with the result term, 
	 * and the result term itself. 
	 * @author odedmagg
	 */
	static public class Result {
		private int _annotatedGenesCount;
		private String _annotation;
		public Result(String annotation, int annotatedGenesCount) {
			_annotation = annotation;
			_annotatedGenesCount = annotatedGenesCount;
		}
		
		public String getAnnotation() {
			return _annotation;
		}
		
		public int getAnnotatedGenes() {
			return _annotatedGenesCount;
		}
	}
	

	private String _scriptFile;
	private String _oboFile;
	private String _annotationsFile;
	public int _genesInGenome;
	final private static String TERMFINDER_PREFIX = "terms_";
	final private static String TERMFINDER_SUFFIX = ".out";	
	
	public TermFinder(double cutoff, int genesInGenome, String scriptFile, String oboFile, String annotationFile) {
		super(cutoff);
		set_scriptFile(scriptFile);
		set_oboFile(oboFile);
		set_annotationsFile(annotationFile);
		_genesInGenome = genesInGenome;
	}
	
	public void set_scriptFile(String _scriptFile) {
		this._scriptFile = _scriptFile;
	}

	public String get_scriptFile() {
		return _scriptFile;
	}

	public void set_oboFile(String _oboFile) {
		this._oboFile = _oboFile;
	}

	public String get_oboFile() {
		return _oboFile;
	}

	public void set_annotationsFile(String _annotationsFile) {
		this._annotationsFile = _annotationsFile;
	}

	public String get_annotationsFile() {
		return _annotationsFile;
	}

	public void set_genesInGenome(int genesCount) {
		_genesInGenome = genesCount;
	}
	
	public int getGenesInGenome() {
		return _genesInGenome;
	}
	
	public void find(List<Cluster> clusters) {
		Calendar cal = Calendar.getInstance();
		long suffix = cal.getTimeInMillis() % 268435456; // 2 ^ 28
		
		String filename = Consts.DATA_DIR + TERMFINDER_PREFIX + suffix;
		String scriptOutputFile = filename + TERMFINDER_SUFFIX;

		saveClustersToFile(clusters, filename);
		runTermFinder(filename);
		loadClusterAnnotations(clusters, scriptOutputFile);

		// Delete temporary files.
		File f = new File(filename);
		f.delete();
		f = new File(scriptOutputFile);
		f.delete();		
	}
	
	private void saveClustersToFile(List<Cluster> clusters, String filename) {
		try {
			// System.out.println("DEBUG: " + filename);
			FileWriter clustersFile = new FileWriter(filename);
			for (Cluster c: clusters) {
				if (c == null) {
					System.out.println("SUCKS");
					return;
				}
				clustersFile.write(c.toString() + "\n");
			}			
			clustersFile.close();
		} catch (IOException ioe) {
			System.err.println("PARFAIT Error: Can't write to file "+ filename +" since:");
			System.out.println(ioe.getMessage());
		}
	}
	
	private void runTermFinder(String inputFile) {
		Runtime run = Runtime.getRuntime();
		// System.out.println("Running: perl " + Consts.SCRIPTS_DIR + _scriptFile + " " + Consts.DATA_DIR + _annotationsFile + " " + Integer.toString(_genesInGenome) + "" + Consts.DATA_DIR + _oboFile + " " + Double.toString(_cutoff) + " " + inputFile); // TEMP TODO REMOVE
		Process runGOTermFinder;
		String[] termFinderCmd = {"perl",
											  Consts.SCRIPTS_DIR + _scriptFile, 
				                              Consts.DATA_DIR + _annotationsFile,
				                              Integer.toString(_genesInGenome),
				                              Consts.DATA_DIR + _oboFile,
				                              Double.toString(_cutoff),				                              
				                              inputFile}; 
/*				  _scriptFile, 
                  _annotationsFile,
                  "7200",
                  _oboFile,
                  "genes3.txt"};				*/
//		System.out.println("Executing: " + termFinderCmd.); // TEMP TODO REMOVE

		try {
			runGOTermFinder = run.exec(termFinderCmd);
			
			InputStream a = runGOTermFinder.getInputStream();
			
			// while (a.available() > 0) {
			// 	a.skip(a.available());
			// }
			BufferedReader in = new BufferedReader(
                    new InputStreamReader(runGOTermFinder.getInputStream()));
			String inputLine;

			// Keep clearing the script's STDOUT pipe...
			while ((inputLine = in.readLine()) != null) {}
				//System.out.println(inputLine); // TEMP TODO remove 
			//}
			in.close();
			
			// TEMP TODO remove 
			/*
            BufferedReader stdInput = new BufferedReader(new 
                    InputStreamReader(runGOTermFinder.getInputStream()));          

               // read the output from the command
               String s = null;
               System.out.println("Here is the standard output of the command:\n");
               while ((s = stdInput.readLine()) != null) {
                   System.out.println(s);
               }
   				*/ // TEMP TODO remove END
              
			int result = runGOTermFinder.waitFor();
			
			if (result != 0) {
				System.err.println("Parfait error: " + _scriptFile + " ended with return code " + result);
			}
			
		}	catch (InterruptedException ine) {
			System.err.println("Parfait error: " + _scriptFile + " was interrupted by another thread");
		} catch (IOException ioe) {
			System.err.print("Parfait error: Can't execute " + _scriptFile + " - ");
			System.err.println(ioe.getMessage());
			System.exit(1);
		}
		// This is the command to run mcl.
		/*
		String[] command ={ Consts.MCL_DIR+"mcl", EDGES_FILE_NAME ,"--abc","-o",CLUSTERS_FILE};
		try {
			//run.exec(moveToDir); // move to the directory of MCL
			runMCL = run.exec(command);
			runMCL.waitFor();
			//MCLoutput = runMCL.getOutputStream();
			//System.out.println(MCLoutput);
		} catch (InterruptedException ine) {
			System.err.println("Running MCL is interrupted by another thread");
		} catch (IOException ioe) {
			System.err.println("Can't execute mcl since:");
			System.err.println(ioe.getMessage());
			System.exit(1);
		} */
		
		
	}
	
	private void loadClusterAnnotations(List<Cluster> clusters, String scriptOutputFile) {
		// TEMP TODO implement.
		BufferedReader read;
		String line;
		try {
			// read = new BufferedReader(new FileReader(Consts.CUR_DIR+CLUSTERS_FILE)); // TEMP TODO Liat version.
			 read = new BufferedReader(new FileReader(scriptOutputFile));
			// skip the first line.
			 Cluster cluster;
			 Iterator<Cluster> iter = clusters.iterator();
			while ((((line = read.readLine()) != null) && (iter.hasNext())) ) {
				cluster = iter.next();
				if (!line.isEmpty()) {
					cluster.setAnnotation(line);
				}
			}
			
			
			read.close();
		} catch (IOException ioe) {
			System.err.println("Can't read the clusters file since: ");
			System.err.println(ioe.getMessage());
			System.exit(1);
		}
	}
}
